import { prisma } from '../db'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import type { User, UserRole } from '@prisma/client'

export interface LoginCredentials {
  email: string
  password: string
}

export interface RegisterData {
  email: string
  username: string
  password: string
  role?: UserRole
}

export interface JWTPayload {
  userId: number
  email: string
  username: string
  role: UserRole
}

export interface GoogleUserInfo {
  googleId: string
  email: string
  username: string
  avatar?: string
}

export class AuthService {
  private static readonly JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'
  private static readonly JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d'
  private static readonly SALT_ROUNDS = 12

  /**
   * 用户注册
   */
  static async register(data: RegisterData): Promise<{ user: Omit<User, 'password'>, token: string }> {
    // 检查邮箱是否已存在
    const existingUser = await prisma.user.findUnique({
      where: { email: data.email }
    })
    if (existingUser) {
      throw new Error('Email already exists')
    }

    // 检查用户名是否已存在
    const existingUsername = await prisma.user.findUnique({
      where: { username: data.username }
    })
    if (existingUsername) {
      throw new Error('Username already exists')
    }

    // 加密密码
    const hashedPassword = await bcrypt.hash(data.password, this.SALT_ROUNDS)

    // 创建用户
    const user = await prisma.user.create({
      data: {
        email: data.email,
        username: data.username,
        password: hashedPassword,
        role: data.role || 'USER'
      }
    })

    // 生成JWT token
    const token = this.generateToken({
      userId: user.id,
      email: user.email,
      username: user.username,
      role: user.role
    })

    // 更新最后登录时间
    await prisma.user.update({
      where: { id: user.id },
      data: { lastLoginAt: new Date() }
    })

    // 记录审计日志
    await this.logAuditAction(user.id, 'USER_REGISTER', 'User', `User registered: ${user.email}`)

    const { password: _, ...userWithoutPassword } = user
    return { user: userWithoutPassword, token }
  }

  /**
   * 用户登录
   */
  static async login(credentials: LoginCredentials): Promise<{ user: Omit<User, 'password'>, token: string }> {
    // 查找用户
    const user = await prisma.user.findUnique({
      where: { email: credentials.email }
    })

    if (!user) {
      throw new Error('Invalid credentials')
    }

    // 检查用户是否激活
    if (!user.isActive) {
      throw new Error('Account is deactivated')
    }

    // 验证密码
    if (!user.password) {
      throw new Error('Please use Google login for this account')
    }

    const isPasswordValid = await bcrypt.compare(credentials.password, user.password)
    if (!isPasswordValid) {
      throw new Error('Invalid credentials')
    }

    // 生成JWT token
    const token = this.generateToken({
      userId: user.id,
      email: user.email,
      username: user.username,
      role: user.role
    })

    // 更新最后登录时间
    await prisma.user.update({
      where: { id: user.id },
      data: { lastLoginAt: new Date() }
    })

    // 记录审计日志
    await this.logAuditAction(user.id, 'USER_LOGIN', 'User', `User logged in: ${user.email}`)

    const { password: _, ...userWithoutPassword } = user
    return { user: userWithoutPassword, token }
  }

  /**
   * Google OAuth 登录/注册
   */
  static async googleAuth(googleUserInfo: GoogleUserInfo): Promise<{ user: Omit<User, 'password'>, token: string, isNewUser: boolean }> {
    // 查找是否已存在Google用户
    let user = await prisma.user.findUnique({
      where: { googleId: googleUserInfo.googleId }
    })

    let isNewUser = false

    if (!user) {
      // 检查邮箱是否已被其他账户使用
      const existingEmailUser = await prisma.user.findUnique({
        where: { email: googleUserInfo.email }
      })

      if (existingEmailUser) {
        // 如果邮箱已存在但没有Google ID，则关联Google账户
        user = await prisma.user.update({
          where: { id: existingEmailUser.id },
          data: {
            googleId: googleUserInfo.googleId,
            avatar: googleUserInfo.avatar || existingEmailUser.avatar
          }
        })
      } else {
        // 创建新用户
        user = await prisma.user.create({
          data: {
            email: googleUserInfo.email,
            username: googleUserInfo.username,
            googleId: googleUserInfo.googleId,
            avatar: googleUserInfo.avatar,
            role: 'USER'
          }
        })
        isNewUser = true
      }
    }

    // 检查用户是否激活
    if (!user.isActive) {
      throw new Error('Account is deactivated')
    }

    // 生成JWT token
    const token = this.generateToken({
      userId: user.id,
      email: user.email,
      username: user.username,
      role: user.role
    })

    // 更新最后登录时间
    await prisma.user.update({
      where: { id: user.id },
      data: { lastLoginAt: new Date() }
    })

    // 记录审计日志
    const action = isNewUser ? 'USER_REGISTER_GOOGLE' : 'USER_LOGIN_GOOGLE'
    await this.logAuditAction(user.id, action, 'User', `Google auth: ${user.email}`)

    const { password: _, ...userWithoutPassword } = user
    return { user: userWithoutPassword, token, isNewUser }
  }

  /**
   * 验证JWT token
   */
  static verifyToken(token: string): JWTPayload {
    try {
      return jwt.verify(token, this.JWT_SECRET) as JWTPayload
    } catch (error) {
      throw new Error('Invalid token')
    }
  }

  /**
   * 生成JWT token
   */
  private static generateToken(payload: JWTPayload): string {
    return jwt.sign(payload, this.JWT_SECRET, {
      expiresIn: this.JWT_EXPIRES_IN
    } as jwt.SignOptions)
  }

  /**
   * 修改密码
   */
  static async changePassword(userId: number, oldPassword: string, newPassword: string): Promise<void> {
    const user = await prisma.user.findUnique({
      where: { id: userId }
    })

    if (!user || !user.password) {
      throw new Error('User not found or password not set')
    }

    // 验证旧密码
    const isOldPasswordValid = await bcrypt.compare(oldPassword, user.password)
    if (!isOldPasswordValid) {
      throw new Error('Invalid old password')
    }

    // 加密新密码
    const hashedNewPassword = await bcrypt.hash(newPassword, this.SALT_ROUNDS)

    // 更新密码
    await prisma.user.update({
      where: { id: userId },
      data: { password: hashedNewPassword }
    })

    // 记录审计日志
    await this.logAuditAction(userId, 'PASSWORD_CHANGE', 'User', 'Password changed')
  }

  /**
   * 重置密码
   */
  static async resetPassword(email: string, newPassword: string): Promise<void> {
    const user = await prisma.user.findUnique({
      where: { email }
    })

    if (!user) {
      throw new Error('User not found')
    }

    // 加密新密码
    const hashedPassword = await bcrypt.hash(newPassword, this.SALT_ROUNDS)

    // 更新密码
    await prisma.user.update({
      where: { id: user.id },
      data: { password: hashedPassword }
    })

    // 记录审计日志
    await this.logAuditAction(user.id, 'PASSWORD_RESET', 'User', 'Password reset')
  }

  /**
   * 记录审计日志
   */
  private static async logAuditAction(
    userId: number | null,
    action: string,
    resource: string,
    details: string,
    ipAddress?: string,
    userAgent?: string
  ): Promise<void> {
    try {
      await prisma.auditLog.create({
        data: {
          userId,
          action,
          resource,
          details,
          ipAddress,
          userAgent
        }
      })
    } catch (error) {
      console.error('Failed to log audit action:', error)
    }
  }
}
